home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / src / demos / OpenGL / backtrace / scene.c++ < prev    next >
C/C++ Source or Header  |  1996-11-11  |  26KB  |  1,052 lines

  1. /*
  2.  * (c) Copyright 1993, Silicon Graphics, Inc.
  3.  * ALL RIGHTS RESERVED 
  4.  * Permission to use, copy, modify, and distribute this software for 
  5.  * any purpose and without fee is hereby granted, provided that the above
  6.  * copyright notice appear in all copies and that both the copyright notice
  7.  * and this permission notice appear in supporting documentation, and that 
  8.  * the name of Silicon Graphics, Inc. not be used in advertising
  9.  * or publicity pertaining to distribution of the software without specific,
  10.  * written prior permission. 
  11.  *
  12.  * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
  13.  * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
  14.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
  15.  * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL SILICON
  16.  * GRAPHICS, INC.  BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
  17.  * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
  18.  * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
  19.  * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
  20.  * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC.  HAS BEEN
  21.  * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
  22.  * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
  23.  * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
  24.  * 
  25.  * US Government Users Restricted Rights 
  26.  * Use, duplication, or disclosure by the Government is subject to
  27.  * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
  28.  * (c)(1)(ii) of the Rights in Technical Data and Computer Software
  29.  * clause at DFARS 252.227-7013 and/or in similar or successor
  30.  * clauses in the FAR or the DOD or NASA FAR Supplement.
  31.  * Unpublished-- rights reserved under the copyright laws of the
  32.  * United States.  Contractor/manufacturer is Silicon Graphics,
  33.  * Inc., 2011 N.  Shoreline Blvd., Mountain View, CA 94039-7311.
  34.  *
  35.  * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
  36.  */
  37. #include <GL/glu.h>
  38. #include <GL/glx.h>
  39.  
  40. #include <math.h>
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43.  
  44. /* XXX */
  45. #include <malloc.h>
  46.  
  47. #include "Unitdisk.h"
  48. #include "scene.h"
  49. #include "rgb.h"
  50.  
  51. const GLfloat I[16] = {
  52.   1, 0, 0, 0,
  53.   0, 1, 0, 0,
  54.   0, 0, 1, 0,
  55.   0, 0, 0, 1};
  56.  
  57. Color white;
  58. Color black;
  59.  
  60. const double M_2PI = 2.0 * M_PI;
  61. const float scene_fudge = .000001;
  62.  
  63. /* Lights are native to the xz plane and are rotated into position - 
  64.  * shadows and refraction will not have to be changed if lights are 
  65.  * just rotating about the z axis */
  66. light lights[] = {
  67.   {{1, 0, 0, 1}, {0, 0, 0, 0}, {1, 0, 0, 0}, 
  68.      {1, 0, 0, 0,  0, 1, 0, 0,   0, 0, 1, 0,   0, 0, 0, 1},
  69.     "Red", 1},
  70.   {{0, 1, 0, 1}, {0, 0, 0, 0}, {0, 1, 0, 0},
  71.      {1, 0, 0, 0,  0, 1, 0, 0,   0, 0, 1, 0,   0, 0, 0, 1},
  72.     "Green", 1},
  73.   {{0, 0, 1, 1}, {0, 0, 0, 0}, {0, 0, 1, 0},
  74.      {1, 0, 0, 0,  0, 1, 0, 0,   0, 0, 1, 0,   0, 0, 0, 1},
  75.     "Blue", 1}
  76. };
  77. GLfloat light_init_position[nlights][4] = 
  78. {{1.5, 0, 2.5, 1}, {1, 0, 3, 1}, {2, 0, 3, 1}};
  79. GLfloat light_init_rotation[nlights] = {135, 0, 90};
  80. GLfloat light_rotation[nlights];
  81.  
  82. Color world_ambient(.25, .25, .25);
  83.  
  84. GLfloat xindex = indices[def_refraction_index].index;
  85.  
  86. GLfloat square_ambient[4] = {.25, .25, .25, 1};
  87. GLfloat square_diffuse[4] = {1, 1, 1, 1};
  88. GLfloat square_specular[4] = {0, 0, 0, 1};
  89.  
  90. const GLfloat fov = 45.0;
  91. GLfloat aspect = 1.0;
  92. GLfloat eyep[3] = {-6, 0, 6};
  93. GLfloat lookp[3] = {0, 0, 1};
  94.  
  95.  
  96.  
  97. static GLXContext glx_context;
  98.  
  99. const int max_args = 20;
  100.  
  101. static int list_square;
  102. static int lists_shadows;
  103. static int lists_refraction;
  104. static int lists_lights = 5;
  105. static int list_sphere = 4;
  106. static int list_spheredisk = 9;
  107. static int list_lights_on = 6;
  108. static int list_lights_off = 7;
  109. static int list_light_draw = 8;
  110.  
  111. int draw_square = 1;
  112. int draw_shadows = 1;
  113. int draw_refraction = 1;
  114. int draw_sphere = 1;
  115. int draw_lights = 1;
  116. int draw_texture = 0;
  117.  
  118. int possible_divisions[] = {10, 20, 30, 40};
  119.  
  120. // Sphere is stored as floats - more efficient
  121. GLfloat *spherepts = NULL;
  122. int nspherepts = 0;
  123. int spherediv = 0;
  124. Point sphere_position = {0, 0, 1, 1};
  125. GLfloat sphere_size = .5;
  126. const GLfloat sphere_ambient[4] = {0, 0, 0, 0};
  127. const GLfloat sphere_specular[4] = {0, 0, 0, 0};
  128. Unitdisk sphere_disk;
  129. static void sphere_build();
  130. static void sphere_list_init();
  131. static void sphere_draw();
  132.  
  133. static void square_list_init();
  134.  
  135. static void lights_init_onoff();
  136. static void lights_init_position();
  137. static void lights_init_position(int i);
  138. static void lights_list_init();
  139. static void lights_list_init(int n);
  140.  
  141. static void light_draw_list_init();
  142.  
  143. Unitdisk disks[nlights];
  144. int diskdiv = possible_divisions[def_divisions_index];
  145. static void disk_build();
  146. static void disk_build(int disk);
  147.  
  148.  
  149. Unitdisk shadows[nlights];
  150. static void shadow_list_init();
  151. static void shadow_list_init(int n);
  152. static void shadow_draw(int n);
  153.  
  154. Unitdisk refraction[nlights];
  155. static void refraction_list_init();
  156. static void refraction_list_init(int n);
  157.  
  158. static void shadow_refraction_full_build();
  159. static void shadow_refraction_full_build(int n);
  160.  
  161. void scene_init();
  162. static void lists_init();
  163. static void lights_init();
  164. static int lights_move(int light, float dr, float dphi, float dtheta, 
  165.                int update);
  166. static void lights_move_update(int light, int dr, int dphi, int dtheta);
  167.  
  168. void scene_draw();
  169.  
  170. void texture_init();
  171. RGBImageRec *teximage = NULL;
  172.  
  173. inline float sign(float a) 
  174. {
  175.   // This is badly written so let's not call it too often, 'k?
  176.   return (a > 0) ? 1 : (a < 0) ? -1 : 0;
  177. }
  178.  
  179. inline double degrees(double a)
  180. {
  181.   return (a * 180.0 / M_PI);
  182. }
  183.  
  184. inline double radians(double a)
  185. {
  186.   return (a * M_PI / 180.0);
  187. }
  188.  
  189. inline double degrees_clamp(double a)
  190. {
  191.   while (a < 0.0) a += 360.0;
  192.   while (a > 360.0) a -= 360.0;
  193.   return a;
  194. }
  195.  
  196. inline double radians_clamp(double a)
  197. {
  198.   while (a < 0.0) a += M_2PI;
  199.   while (a > M_2_PI) a -= M_2PI;
  200.   return a;
  201. }
  202.  
  203. void scene_init()
  204. {
  205.   int i;
  206.  
  207.   white.c[0] = white.c[1] = white.c[2] = white.c[3] = 1;
  208.   black.c[0] = black.c[1] = black.c[2] = 0;
  209.   black.c[3] = 1;
  210.  
  211.   lists_init();
  212.  
  213.  
  214.   for (i = 0; i < nlights; i++) {
  215.     lights[i].pos = light_init_position[i];
  216.     light_rotation[i] = light_init_rotation[i];
  217.     lights_init_position(i);
  218.   }
  219.  
  220.   divisions_change(possible_divisions[def_divisions_index]);
  221.  
  222.   lights_init_onoff();
  223.   lights_init();
  224.   lights_init_position();
  225.  
  226.   texture_init();
  227.  
  228.   glClearStencil(0);
  229.  
  230.   // This is for profiling
  231.   // exit(0);
  232. }
  233.  
  234. static void scene_project()
  235. {
  236.   glMatrixMode(GL_PROJECTION);
  237.   gluPerspective(fov, aspect, 0.01, 20.0);
  238.   gluLookAt(eyep[0], eyep[1], eyep[2], lookp[0], lookp[1], lookp[2],
  239.             1, 0, 0);
  240. }
  241.  
  242. static void scene_rasterize()
  243. {
  244.   int i;
  245.  
  246.   glLoadName(name_square);
  247.   if (draw_square) {
  248.     if (draw_texture) glEnable(GL_TEXTURE_2D);
  249.     glCallList(list_square);
  250.     glDisable(GL_TEXTURE_2D);
  251.   }
  252.   if (draw_shadows) 
  253.     for (i = 0; i < nlights; i++) 
  254.       if (lights[i].on) {
  255.     glPushMatrix();
  256.     glRotatef(-light_rotation[i], 0, 0, 1);
  257.     glCallList(lists_shadows + i);
  258.     glPopMatrix();
  259.       }
  260.   if (draw_refraction) 
  261.     for (i = 0; i < nlights; i++) 
  262.       if (lights[i].on) {
  263.     glPushMatrix();
  264.     glRotatef(-light_rotation[i], 0, 0, 1);
  265.     glCallList(lists_refraction + i);
  266.     glPopMatrix();
  267.       }
  268.  
  269.   glLoadName(name_sphere);
  270.   /* Drawing the sphere here makes the sphere visible through itself when we
  271.    * do the refraction redraw hack -- for now, just don't draw it */
  272.   //  if (draw_sphere) glCallList(list_sphere);
  273.  
  274.   for (i = 0; i < nlights; i++) 
  275.     if (draw_lights) glCallList(lists_lights + i);
  276. }
  277.  
  278. /* This draws an image of the scene seen through the sphere */
  279. static void scene_draw_refracted()
  280. {
  281.   int i;
  282.  
  283.   if (!draw_sphere) return;
  284.  
  285.  
  286.   /* Draw an image of the sphere into the stencil plane  - 
  287.    * must do this every time in case the lights have moved in front
  288.    * of it */
  289.   glEnable(GL_STENCIL_TEST);
  290.   glClearStencil(0);
  291.   glClear(GL_STENCIL_BUFFER_BIT);
  292.   glStencilFunc(GL_ALWAYS, 0x1, 0x1);
  293.   glStencilOp(GL_REPLACE, GL_KEEP, GL_REPLACE);
  294.   
  295.   glColorMask(0, 0, 0, 0);
  296.  
  297.   glMatrixMode(GL_PROJECTION);
  298.   glLoadIdentity();
  299.   scene_project();
  300.  
  301.   glEnable(GL_DEPTH_TEST);
  302.   glEnable(GL_CULL_FACE);
  303.   glCallList(list_sphere);
  304.   glDisable(GL_CULL_FACE);
  305.   glDisable(GL_DEPTH_TEST);
  306.  
  307.   glColorMask(1, 1, 1, 1);
  308.  
  309.  
  310.   /* Set up a transform with a wider field of view  - this is inaccurate 
  311.    * but I don't have time to do it right */
  312.   glMatrixMode(GL_PROJECTION);
  313.   glLoadIdentity();
  314.   gluPerspective(fov * xindex, aspect, 0.01, 20.0);
  315.   gluLookAt(eyep[0], eyep[1], eyep[2], lookp[0], lookp[1], lookp[2],
  316.             1, 0, 0);
  317.   glMatrixMode(GL_MODELVIEW);
  318.   glLoadIdentity();
  319.  
  320.  
  321.   /* Set up the stencil stuff which will be used to draw the image */
  322.   glStencilFunc(GL_NOTEQUAL, 0x0, 0xffffffff);
  323.   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  324.  
  325.  
  326.   /* Draw the image, gambling that we'll never see anything but the
  327.    * floor through the table */
  328.   glLoadName(name_sphere);
  329.   if (draw_texture) glEnable(GL_TEXTURE_2D);
  330.   if (draw_square) glCallList(list_square);
  331.   if (draw_shadows)     
  332.     for (i = 0; i < nlights; i++) 
  333.       if (lights[i].on) {
  334.     glPushMatrix();
  335.     glRotatef(-light_rotation[i], 0, 0, 1);
  336.     glCallList(lists_shadows + i);
  337.     glPopMatrix();
  338.       }
  339.   if (draw_refraction) 
  340.     for (i = 0; i < nlights; i++) 
  341.       if (lights[i].on) {
  342.     glPushMatrix();
  343.     glRotatef(-light_rotation[i], 0, 0, 1);
  344.     glCallList(lists_refraction + i);
  345.     glPopMatrix();
  346.       }
  347.   glDisable(GL_TEXTURE_2D);
  348.  
  349.  
  350.   /* Draw the sphere to make it look like it
  351.    * has some substance */
  352.   glMatrixMode(GL_PROJECTION);
  353.   glLoadIdentity();
  354.   scene_project();
  355.   glCallList(list_spheredisk);
  356.  
  357.   glDisable(GL_STENCIL_TEST);
  358. }
  359.  
  360.  
  361. void scene_draw() 
  362. {
  363.   glMatrixMode(GL_PROJECTION);
  364.   glLoadIdentity();
  365.  
  366.   glMatrixMode(GL_MODELVIEW);
  367.   glLoadIdentity();
  368.  
  369.   scene_project();
  370.  
  371.   /* Should draw an image of the square into the stencil buffer 
  372.    * to make sure that refractions which are not on the square do not get
  373.    * drawn, but it can wait. */
  374.  
  375.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  376.   scene_rasterize();
  377.  
  378.   scene_draw_refracted();
  379.  
  380. }
  381.  
  382. const int pick_maxz = 0xffffffff;
  383.  
  384. int scene_pick(GLdouble x, GLdouble y)
  385. {
  386.   GLuint buffer[128];
  387.   GLint vp[4], nhits, nnames;
  388.   GLuint minz, hit = name_background;
  389.   GLint i, j;
  390.   
  391.   glMatrixMode(GL_MODELVIEW);
  392.   glLoadIdentity();
  393.   
  394.   glMatrixMode(GL_PROJECTION);
  395.   glLoadIdentity();
  396.   
  397.   glGetIntegerv(GL_VIEWPORT, vp);
  398.   
  399.   glSelectBuffer(128, buffer);
  400.   glRenderMode(GL_SELECT);
  401.  
  402.   // Where is this supposed to go, anyway?
  403.   gluPickMatrix(x, vp[3] - y, 1, 1, vp);
  404.   
  405.   scene_project();
  406.  
  407.   glMatrixMode(GL_MODELVIEW);
  408.  
  409.   glInitNames();
  410.   glPushName(name_background);
  411.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  412.   scene_rasterize();
  413.   glFlush();
  414.   nhits = glRenderMode(GL_RENDER);
  415.  
  416.   minz = pick_maxz;
  417.   for (i = j = 0; j < nhits; j++) {
  418.     nnames = buffer[i];
  419.     i++;
  420.     if (buffer[i] < minz) {
  421.       minz = buffer[i];
  422.       hit = buffer[i + 1 + nnames];
  423.     } 
  424.     i++;
  425.     i += nnames + 1;
  426.   }
  427.   if (minz == pick_maxz) return name_background;
  428.   else return hit;
  429. }
  430.  
  431. void scene_reset_lights() 
  432. {
  433.   int i;
  434.   for (i = 0; i < nlights; i++) {
  435.     lights[i].pos = light_init_position[i];
  436.     light_rotation[i] = light_init_rotation[i];
  437.   }
  438.   lights_init_position();
  439.   lights_list_init();
  440. }
  441.  
  442. static void square_list_init()
  443. {
  444.   GLfloat x, y, inc;
  445.   int i, j;  
  446.   glNewList(list_square, GL_COMPILE);
  447.   glLoadName(name_square);
  448.   glNormal3f(0, 0, 1);
  449.   glEnable(GL_LIGHTING);
  450.   glCallList(list_lights_on);
  451.   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, square_ambient);
  452.   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, square_diffuse);
  453.   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, square_specular);
  454.   inc = 10.0 / diskdiv;
  455.   glEnable(GL_CULL_FACE);
  456.  
  457.   for (i = 0, y = -5.0; i < diskdiv; i++, y += inc) {
  458.     glBegin(GL_TRIANGLE_STRIP);
  459.     for (j = 0, x = -5.0; j <= diskdiv; j++, x += inc) {
  460.       glTexCoord2f(x, y + inc);
  461.       glVertex2f(x, y + inc);
  462.       glTexCoord2f(x, y);
  463.       glVertex2f(x, y);
  464.     }
  465.     glEnd();
  466.   }
  467.  
  468.   glDisable(GL_CULL_FACE);
  469.   glCallList(list_lights_off);
  470.   glDisable(GL_LIGHTING);
  471.   glEndList();
  472. }
  473.  
  474. static void spheredisk_list_init()
  475. {
  476.   glNewList(list_spheredisk, GL_COMPILE);
  477.   glEnable(GL_BLEND);
  478.   glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
  479.   glEnable(GL_LIGHTING);
  480.   glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
  481.   glEnable(GL_COLOR_MATERIAL);
  482.   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, sphere_ambient);
  483.   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, sphere_specular);
  484.   glCallList(list_lights_on);
  485.   sphere_disk.draw();
  486.   glCallList(list_lights_off);
  487.   glDisable(GL_COLOR_MATERIAL);
  488.   glDisable(GL_LIGHTING);
  489.   glDisable(GL_BLEND);
  490.   glEndList();
  491. }
  492.  
  493. void lights_onoff(int light, int val)
  494. {
  495.   lights[light].on = val;
  496.   lights_init_onoff();
  497.   lights_list_init(light);
  498.   square_list_init();
  499. }
  500.  
  501. void refraction_change(GLfloat refraction)
  502. {
  503.   if (refraction == xindex) return;
  504.   xindex = refraction;
  505.   shadow_refraction_full_build();
  506.   refraction_list_init();
  507. }
  508.  
  509. void divisions_change(int divisions)
  510. {
  511.   Point eye, look;
  512.  
  513.   if (divisions != spherediv) {
  514.     spherediv = divisions;
  515.  
  516.     light_draw_list_init();
  517.     lights_list_init();
  518.  
  519.     sphere_disk.set_divisions(spherediv, spherediv);
  520.     sphere_disk.fill_points();
  521.     sphere_disk.set_colors(white);
  522.     sphere_disk.scale_alpha_by_z();
  523.     eye = eyep;
  524.     look = lookp;
  525.     sphere_disk.face_direction((eye - look).unit());
  526.     sphere_disk.copy_normals_from_points();
  527.     sphere_disk.scale_translate(sphere_size, sphere_position);
  528.     sphere_build();
  529.     sphere_list_init();
  530.  
  531.     diskdiv = divisions;
  532.     disk_build();
  533.     shadow_refraction_full_build();
  534.     square_list_init();
  535.     spheredisk_list_init();
  536.     shadow_list_init();
  537.     refraction_list_init();
  538.   }
  539. }
  540.  
  541. int scene_move(int name, float dr, float dphi, float dtheta, int update)
  542. {
  543.   switch(name) {
  544.   case name_background:
  545.     return 0;
  546.   case name_square:
  547.     return 0;
  548.   case name_sphere:
  549.     return 0;
  550.   default:
  551.     if (name < name_lights || name > name_lights + nlights) return 0;
  552.     return lights_move(name - name_lights, dr, dphi, dtheta, update);
  553.   }
  554. }
  555.  
  556. void scene_move_update(int name, int dr, int dphi, int dtheta)
  557. {
  558.   switch(name) {
  559.   case name_background:
  560.     break;
  561.   case name_square:
  562.     break;
  563.   case name_sphere:
  564.     break;
  565.   default:
  566.     if (name < name_lights || name > name_lights + nlights) break;
  567.     lights_move_update(name - name_lights, dr, dphi, dtheta);
  568.     break;
  569.   }
  570. }
  571.  
  572.  
  573. static void lights_init_onoff()
  574. {
  575.   int i;
  576.   
  577.   glNewList(list_lights_on, GL_COMPILE);
  578.   for (i = 0; i < nlights; i++) 
  579.     if (lights[i].on) glEnable(GL_LIGHT0 + i);
  580.     else glDisable(GL_LIGHT0 + i);
  581.   glEndList();
  582.   
  583.   glNewList(list_lights_off, GL_COMPILE);
  584.   for (i = 0; i < nlights; i++) glDisable(GL_LIGHT0 + i);
  585.   glEndList();
  586. }
  587.  
  588.  
  589.  
  590. static void lights_init_position()
  591. {
  592.   int i;
  593.  
  594.   for (i = 0; i < nlights; i++) lights_init_position(i);
  595.  
  596. }
  597.  
  598. static void lights_init_position(int i) 
  599. {
  600.   Point l, d;
  601.  
  602.   glMatrixMode(GL_MODELVIEW);
  603.   glLoadIdentity();
  604.   glMatrixMode(GL_PROJECTION);
  605.   glLoadIdentity();
  606.   
  607.   l = lights[i].pos;
  608.   l.pt[0] = lights[i].pos.pt[0] * cos(radians(light_rotation[i]));
  609.   l.pt[1] = lights[i].pos.pt[0] * -sin(radians(light_rotation[i]));
  610.   d = (sphere_position - l).unit();
  611.   glLightfv(GL_LIGHT0 + i, GL_POSITION, l.pt);
  612.   glLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, d.pt);
  613. }
  614.  
  615. static void lights_list_init()
  616. {
  617.   int i;
  618.   for (i = 0; i < nlights; i++) lights_list_init(i);
  619. }
  620.  
  621. static void lights_list_init(int n)
  622. {
  623.   Color c;
  624.  
  625.   glNewList(lists_lights + n, GL_COMPILE);
  626.   if (lights[n].on) {
  627.     glLoadName(name_lights + n);
  628.     
  629.     glEnable(GL_DEPTH_TEST);
  630.     glEnable(GL_LIGHTING);
  631.     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
  632.     glCallList(list_lights_on);
  633.  
  634.     c = lights[n].diffuse;
  635.     glMaterialfv(GL_BACK, GL_AMBIENT, c.c);
  636.     glMaterialfv(GL_BACK, GL_DIFFUSE, black.c);
  637.     glMaterialfv(GL_BACK, GL_SPECULAR, black.c);
  638.  
  639.     glMaterialfv(GL_FRONT, GL_AMBIENT, (c * .75).c);
  640.     glMaterialfv(GL_FRONT, GL_DIFFUSE, white.c);
  641.     glMaterialfv(GL_FRONT, GL_SPECULAR, white.c);
  642.  
  643.     glMatrixMode(GL_MODELVIEW);
  644.     glPushMatrix();
  645.     glRotatef(-light_rotation[n], 0, 0, 1);
  646.     glTranslatef(lights[n].pos.pt[0], lights[n].pos.pt[1], 
  647.          lights[n].pos.pt[2]);
  648.     glRotatef(-degrees(atan2(lights[n].pos.pt[2] - sphere_position.pt[2],
  649.                  lights[n].pos.pt[0])), 0, 1, 0);
  650.     glCallList(list_light_draw);
  651.     glPopMatrix();
  652.  
  653.     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
  654.     glDisable(GL_LIGHTING);
  655.     glCallList(list_lights_off);
  656.     glDisable(GL_DEPTH_TEST);
  657.   } else {
  658.     /* 5.0.1 for Elans seems to object strongly to replacing
  659.      * empty display lists, so will put some stupid command
  660.      * in here */
  661.     glColor3f(0, 0, 0);
  662.   }
  663.   glEndList();
  664. }
  665.  
  666. static void light_draw_list_init()
  667. {
  668.   float c, s;
  669.   int t;
  670.  
  671.   glNewList(list_light_draw, GL_COMPILE);
  672.   glEnable(GL_NORMALIZE);
  673.   glMatrixMode(GL_MODELVIEW);
  674.   glPushMatrix();
  675.   glScalef(.25, .15, .15);
  676.   glBegin(GL_QUAD_STRIP);
  677.   for (t = 0; t <= spherediv; t++) {
  678.     c = cos(M_2PI * (float)t / (float)spherediv);
  679.     s = sin(M_2PI * (float)t / (float)spherediv);
  680.     glNormal3f(.25, .968*s, .968*c);
  681.     glVertex3f(0, s, c);
  682.     glVertex3f(1, .75*s, .75*c);
  683.   }
  684.   glEnd();
  685.   glNormal3f(1, 0, 0);
  686.   glBegin(GL_TRIANGLE_STRIP);
  687.   for (t = 0; t <= spherediv; t++) {
  688.     c = cos(M_2PI * (float)t / (float)spherediv);
  689.     s = sin(M_2PI * (float)t / (float)spherediv);
  690.     glVertex3f(1, .75*s, .75*c);
  691.     glVertex3f(1, 0, 0);
  692.   }
  693.   glEnd();
  694.   glPopMatrix();
  695.   glDisable(GL_NORMALIZE);
  696.   glEndList();
  697. }
  698.  
  699. static void lights_init()
  700. {
  701.   int i;
  702.  
  703.   for (i = 0; i < nlights; i++) {
  704.     glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, lights[i].diffuse);
  705.     glLightfv(GL_LIGHT0 + i, GL_SPECULAR, black.c);
  706.     glLightfv(GL_LIGHT0 + i, GL_AMBIENT, black.c);
  707.     glLightf(GL_LIGHT0 + i, GL_SPOT_EXPONENT, 4);
  708.     glLightf(GL_LIGHT0 + i, GL_SPOT_CUTOFF, 90);
  709.   }
  710.  
  711.   glLightfv(GL_LIGHT0 + nlights, GL_DIFFUSE, black.c);
  712.   glLightfv(GL_LIGHT0 + nlights, GL_SPECULAR, black.c);
  713.   glLightfv(GL_LIGHT0 + nlights, GL_AMBIENT, world_ambient.c);
  714.   glEnable(GL_LIGHT0 + nlights);
  715.  
  716.   /* GL_LIGHT0 + nlights + 1 willl eventually be used to draw the 
  717.    * refractions - stay tuned. */
  718.   glLightfv(GL_LIGHT0 + nlights + 1, GL_DIFFUSE, black.c);
  719.   glLightfv(GL_LIGHT0 + nlights + 1, GL_SPECULAR, black.c);
  720.   glLightfv(GL_LIGHT0 + nlights + 1, GL_AMBIENT, white.c);
  721. }
  722.  
  723. static int lights_move(int light, float dr, float dphi, float dtheta,
  724.                int update)
  725. {
  726.   float cphi, sphi, x, y;
  727.   float r;
  728.   Point l, dl;
  729.  
  730.   if (!(dr || dphi || dtheta)) return 0;
  731.  
  732.   l = lights[light].pos - sphere_position;
  733.  
  734.   if (dr) {
  735.     dl = l + l*dr;
  736.     if (dl.mag() > sphere_size) l = dl;
  737.   }
  738.   
  739.   if (dphi) {
  740.     cphi = cos(dphi);
  741.     sphi = sin(dphi);
  742.     y = -l.pt[0]*sphi + l.pt[2]*cphi;
  743.     
  744.     /* This hack keeps with light from getting below the sphere - 
  745.      * the projection sections would completely freak if this ever
  746.      * happened  - sphere_size is multiplied by two as a fudge factor*/
  747.     if (y < 2.0*sphere_size) {
  748.       dphi = atan2(l.pt[2] - 2.0*sphere_size, l.pt[0]);
  749.       cphi = cos(dphi);
  750.       sphi = sin(dphi);
  751.       
  752.     }
  753.     x = l.pt[0];
  754.     l.pt[0] = x*cphi + l.pt[2]*sphi;
  755.     l.pt[2] = -x*sphi + l.pt[2]*cphi;
  756.   }
  757.  
  758.   if (dtheta) {
  759.     light_rotation[light] += degrees(dtheta);
  760.     light_rotation[light] = degrees_clamp(light_rotation[light]);
  761.   }
  762.  
  763.   lights[light].pos = l + sphere_position;
  764.   lights[light].pos.pt[3] = 1;
  765.  
  766.   lights_init_position(light);
  767.   lights_list_init(light);
  768.  
  769.   if (update) lights_move_update(light, dr ? 1 : 0, dphi ? 1 : 0, 
  770.                  dtheta ? 1 : 0);
  771.   return 1;
  772. }
  773.  
  774. static void lights_move_update(int light, int dr, int dphi, 
  775.                    int dtheta)
  776. {
  777.   if (dr) {
  778.     disk_build(light);
  779.     shadow_refraction_full_build(light);
  780.     shadow_list_init(light);
  781.     refraction_list_init(light);  
  782.   } else if (dphi) {
  783.     shadow_refraction_full_build(light);
  784.     shadow_list_init(light);
  785.     refraction_list_init(light);
  786.   } else if (dtheta) {
  787.   }
  788.  
  789. }
  790.  
  791.  
  792.  
  793.  
  794. static int get_lists(int size)
  795. {
  796.   int i;
  797.   i = glGenLists(size);
  798.   if (size && !i) {
  799.     fprintf(stderr, "Unable to allocate %d display lists.\n");
  800.     exit(1);
  801.   }
  802.   return i;
  803. }
  804.  
  805. static void lists_init()
  806. {
  807.   list_square = get_lists(1);
  808.   lists_shadows = get_lists(nlights);
  809.   lists_refraction = get_lists(nlights);
  810.   lists_lights = get_lists(nlights);
  811.   list_sphere = get_lists(1);
  812.   list_spheredisk = get_lists(1);
  813.   list_lights_on = get_lists(1);
  814.   list_lights_off = get_lists(1);
  815.   list_light_draw = get_lists(1);
  816.  
  817. //  sphere_build();
  818. }
  819.  
  820. static inline int sphere_npoints() 
  821. {
  822.   return (spherediv+1)*spherediv*3;
  823. }
  824.  
  825. void sphere_build()
  826. {
  827.   int nspherepts;
  828.   int r, t, index;
  829.   float c, s;
  830.       
  831.   delete spherepts;
  832.   nspherepts = sphere_npoints();
  833.   if (nspherepts == 0) return;
  834.   spherepts = new GLfloat[nspherepts];
  835.  
  836.   index = 0;
  837.   for (r = 0; r <= spherediv; r++) {
  838.     spherepts[index++] = sin(M_PI * (float)r / (float)spherediv);
  839.     spherepts[index++] = 0;
  840.     spherepts[index++] = -cos(M_PI * (float)r / (float)spherediv);
  841.   }
  842.   for (t = 1; t < spherediv; t++) {
  843.     c = cos(2.0 * M_PI * (float)t / (float)spherediv);
  844.     s = sin(2.0 * M_PI * (float)t / (float)spherediv);
  845.     for (r = 0; r <= spherediv; r++) {
  846.       spherepts[index++] = c*spherepts[r*3];
  847.       spherepts[index++] = s*spherepts[r*3];
  848.       spherepts[index++] = spherepts[r*3 + 2];
  849.     }
  850.   }
  851.  
  852. }
  853.  
  854. void sphere_list_init()
  855. {
  856.   glNewList(list_sphere, GL_COMPILE);
  857.   sphere_disk.draw_by_perimeter();
  858.   glEndList();
  859. }  
  860.  
  861. void sphere_draw()
  862. {
  863.   int r, t, p1, p2;
  864.  
  865.   for (t = 1; t < spherediv; t++) {
  866.     glBegin(GL_QUAD_STRIP);
  867.     p1 = (t - 1) * (spherediv + 1);
  868.     p2 = t * (spherediv + 1);
  869.     for (r = 0; r <= spherediv; r++, p1++, p2++) {
  870.       glNormal3fv(&spherepts[p1*3]);
  871.       glVertex3fv(&spherepts[p1*3]);
  872.       glNormal3fv(&spherepts[p2*3]);
  873.       glVertex3fv(&spherepts[p2*3]);
  874.     }
  875.     glEnd();
  876.   }
  877.  
  878.   glBegin(GL_QUAD_STRIP); 
  879.   p1 = (spherediv + 1) * (spherediv - 1);
  880.   p2 = 0;
  881.   for (r = 0; r <= spherediv; r++, p1++, p2++) {
  882.     glNormal3fv(&spherepts[p1*3]);
  883.     glVertex3fv(&spherepts[p1*3]);
  884.     glNormal3fv(&spherepts[p2*3]);
  885.     glVertex3fv(&spherepts[p2*3]);
  886.   }
  887.   glEnd();
  888. }
  889.  
  890. static void disk_build()
  891. {
  892.   int i;
  893.   for (i = 0; i < nlights; i++) disk_build(i);
  894. }
  895.  
  896. static void disk_build(int disk)
  897. {
  898.   Point light;
  899.   light = lights[disk].pos;
  900.  
  901.   disks[disk].free_points_normals();
  902.   disks[disk].free_colors();
  903.  
  904.   disks[disk].set_divisions(diskdiv, diskdiv);
  905.   disks[disk].set_angle(2.0 * 
  906.             acos(sphere_size / light.dist(sphere_position)));
  907.   disks[disk].fill_points();
  908. }
  909.  
  910. static void shadow_list_init()
  911. {
  912.   int i;
  913.   for (i = 0; i < nlights; i++) shadow_list_init(i);
  914. }
  915.  
  916. static void shadow_list_init(int n)
  917. {
  918.   Color c(square_ambient[0], square_ambient[1], square_ambient[2]);
  919.  
  920.   c *= world_ambient;
  921.  
  922.   glNewList(lists_shadows + n, GL_COMPILE);
  923.   glColorMask(lights[n].shadow_mask[0], lights[n].shadow_mask[1],
  924.           lights[n].shadow_mask[2], lights[n].shadow_mask[3]);
  925.   glDisable(GL_DEPTH_TEST);
  926.   glColor3fv(c.c);
  927.   shadows[n].draw_by_perimeter(0, 0, 1);
  928.   glColorMask(1, 1, 1, 1);
  929.   glEndList();
  930. }
  931.  
  932. static void refraction_list_init()
  933. {
  934.   int i;
  935.   for (i = 0; i < nlights; i++) refraction_list_init(i);
  936. }
  937.  
  938. static void refraction_list_init(int n) {
  939.   /* This could be loads simpler if it weren't for the texture mapping -
  940.    * that's where all this weirdness with GL_LIGHT0 + nlights + 1 comes 
  941.    * in */
  942.   glNewList(lists_refraction + n, GL_COMPILE);
  943.  
  944.   glEnable(GL_LIGHTING);
  945.   glCallList(list_lights_off);
  946.   /* This is white ambient light */
  947.   glEnable(GL_LIGHT0 + nlights + 1);
  948.   glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, black.c);
  949.   glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black.c);
  950.   glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT);
  951.   glEnable(GL_COLOR_MATERIAL);
  952.  
  953.   glBlendFunc(GL_ONE, GL_ONE);
  954.   glEnable(GL_BLEND);
  955.  
  956.   glDisable(GL_DEPTH_TEST);
  957.   refraction[n].draw();
  958.  
  959.   glDisable(GL_BLEND);
  960.  
  961.   glDisable(GL_COLOR_MATERIAL);
  962.   glDisable(GL_LIGHT0 + nlights + 1);
  963.   glDisable(GL_LIGHTING);
  964.  
  965.   glEndList();
  966. }
  967.  
  968. static void shadow_refraction_full_build()
  969. {
  970.   int i;
  971.   for (i = 0; i < nlights; i++) shadow_refraction_full_build(i);
  972. }
  973.  
  974. /* This entire function is written a bit oddly... */
  975. static void shadow_refraction_full_build(int n)
  976. {
  977.   Color c;
  978.   float dist_light;
  979.   Point dlight, zaxis;
  980.  
  981.   /* Make sure that we're starting over from scratch */
  982.   shadows[n].free_points_normals();
  983.   shadows[n].free_colors();
  984.   refraction[n].free_points_normals();
  985.   refraction[n].free_colors();
  986.  
  987.   dlight = lights[n].pos - sphere_position;
  988.   dist_light = dlight.mag();
  989.   dlight.unitize();
  990.   zaxis.pt[0] = 0;
  991.   zaxis.pt[1] = 0;
  992.   zaxis.pt[2] = 1;
  993.  
  994.   shadows[n].set_divisions(disks[n].get_rdivisions(), 
  995.                disks[n].get_tdivisions());
  996.   refraction[n].set_divisions(disks[n].get_rdivisions(), 
  997.                   disks[n].get_tdivisions());
  998.  
  999.   shadows[n].alloc_points();
  1000.   shadows[n].face_direction(dlight, disks[n]);
  1001.   shadows[n].scale_translate(sphere_size, sphere_position);
  1002.  
  1003.   c = square_diffuse;
  1004.   c *= lights[n].diffuse; 
  1005.  
  1006.   refraction[n].copy_points(disks[n]);
  1007.   refraction[n].set_colors(c);
  1008.   refraction[n].scale_colors_by_z();
  1009.  
  1010.   refraction[n].scale(sphere_size);
  1011.   refraction[n].refract_normals(zaxis * dist_light, xindex);
  1012.   refraction[n].face_direction(dlight);
  1013.  
  1014.   refraction[n].project_borrow_points(shadows[n]);  
  1015.   refraction[n].free_normals();
  1016.   shadows[n].project(lights[n].pos);
  1017.   if (xindex != 1.0) refraction[n].scale_colors_by_darea(shadows[n]);
  1018. }
  1019.  
  1020. int scene_load_texture(char *texfile)
  1021. {
  1022. #ifdef TEXTURE
  1023.   teximage = rgbImageLoad(texfile);
  1024. #else
  1025.   teximage = NULL;
  1026. #endif
  1027.  
  1028.   if (teximage == NULL) return 0;
  1029.   else return 1;
  1030. }
  1031.  
  1032. void texture_init()
  1033. {
  1034.   if (teximage == NULL) return;
  1035.  
  1036.   gluBuild2DMipmaps(GL_TEXTURE_2D, 3, teximage->sizeX, teximage->sizeY,
  1037.             GL_RGB, GL_UNSIGNED_BYTE, teximage->data);
  1038.  
  1039.   glMatrixMode(GL_TEXTURE);
  1040.   glLoadIdentity();
  1041.   glRotatef(90, 0, 0, 1);
  1042.   /* This scales the texture so that it fits on the square */
  1043.   glTranslatef(.5, .5, 0);
  1044.   glScalef(.1, .1, 1);
  1045.   glMatrixMode(GL_MODELVIEW);
  1046.  
  1047.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, 
  1048.          GL_NEAREST_MIPMAP_NEAREST);
  1049.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
  1050.          GL_LINEAR);
  1051. }
  1052.